package com.example.code;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.baomidou.mybatisplus.generator.function.ConverterFileName;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * MyBatisPlus 代码生成器
 *
 * @author 郑玎
 * @date 2022-2-21
 */
public class MyBatisPlusGenerator {
    
    /**
     * 每次使用时请在这里修改 模块名 和 表名
     */
    private static final String ModuleName = "tree"; // 模块名
    private static final String TableNames = "user,user_menu"; // 表名,多个表以逗号分隔
    
    // 数据源配置
    private static final String DATASOURCE_URL = "jdbc:mysql://localhost:3306/demo_tree";
    private static final String DATASOURCE_USERNAME = "root";
    private static final String DATASOURCE_password = "123";
    
    // 全局配置
    //private static final boolean FileOverride = false; // 生成时是否覆盖已有文件（慎重!!!）
    //private static final boolean EnableSwagger = true; // 是否启用 Swagger 注解
    
    // 文件路径配置
    private static final String BaseDir = "\\src\\main\\java"; // Maven 项目 固定就用这个
    private static final String MapperXmlDir = "\\src\\main\\resources\\mappers"; // MapperXml 文件路径
    
    // 包名配置
    private static final String ParentPackage = "com.example"; // 一个项目配置一次就够了
    private static final String EntityPackage = "bean"; // 实体类 包名
    private static final String MapperPackage = "mapper"; // Mapper接口 包名
    private static final String ServicePackage = "service"; // Service接口 包名
    private static final String ServiceImplPackage = "service.impl"; // ServiceImpl实现类 包名
    private static final String ControllerPackage = "controller"; // Controller 包名
    
    // 策略配置
    private static final String TablePrefix = "t_, c_, xf_"; // 表名前缀. 生成 Java 文件时会忽略表名前缀
    private static final String VersionColumnName = "version"; // 乐观锁 数据库表列名. 如果存在对应列会给生成的实体类字段加上@Version注解
    private static final String VersionPropertyName = "version"; // 乐观锁 实体类字段名
    private static final String LogicDeleteColumnName = "is_deleted"; // 逻辑删除 数据库表列名. 如果存在对应列会给生成的实体类字段加上@Logic注解
    private static final String LogicDeletePropertyName = "isDeleted"; // 逻辑删除 实体类字段名
    private static final String CreateTimeColumnName = "create_time"; // 自动填充字段 创建时间
    private static final String UpdateTimeColumnName = "update_time"; // 自动填充字段 更新时间
    private static final String IgnoreColumns = "hello, world"; // 需要忽略的数据库表字段
    
    // 其他信息
    private static final String Author = "ZhengDing";
    private static final String CommentDate = "yyyy-MM-dd HH:mm:ss";
    
    public static void main(String[] args) {
        generate();
    }
    
    public static void generate() {
        // 将此文件放在项目任意合法位置时, getCanonicalPath 可以正确返回项目根路径
        String ProjectDir = getCanonicalPath();
        String outputDir = ProjectDir + BaseDir;
        //String[] tableNameList = StringUtils.delimitedListToStringArray(TableNames, ",");
        //List<String> IncludeTables = Arrays.asList(tableNameList);
        List<String> IncludeTables = delimitedStringToStringList(TableNames);
        String mapperXmlDir = ProjectDir + MapperXmlDir;
        
        FastAutoGenerator.create(DATASOURCE_URL, DATASOURCE_USERNAME, DATASOURCE_password)
                .globalConfig(builder -> {
                    builder.author(Author) // 设置作者
                            .commentDate(CommentDate)
                            .disableOpenDir() // 完成后不打开文件夹
                            .enableSwagger() // 开启 swagger 模式
                            .outputDir(outputDir) // 指定输出目录
                            //.enableKotlin()
                            .fileOverride(); // 如果确定需要覆盖之前的文件, 请去掉此注释. 想清楚再用!!!
                })
                .packageConfig(builder -> {
                    builder.parent(ParentPackage) // 设置父包名
                            .moduleName(ModuleName) // 设置父包模块名
                            .controller(ControllerPackage) // 设置生成的控制器包名; 默认为 controller
                            .service(ServicePackage) // service包名; 默认为 service
                            .serviceImpl(ServiceImplPackage) // serviceImpl包名
                            .mapper(MapperPackage) // mapper包名
                            .entity(EntityPackage) // 实体类包名; 默认为 entity
                            //.xml("mapperXml") // mapperXml包名; 如果配置此项, mapperXml 文件会生成到 controller 同级目录而不是 resources 目录
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, mapperXmlDir)); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude(IncludeTables)
                            .addExclude()
                            .addTablePrefix(delimitedStringToStringArray(TablePrefix))
                            //.addTableSuffix()
                            //.addFieldPrefix()
                            //.addFieldSuffix()
                            //.enableCapitalMode()
                            //.enableSchema()
                            //.enableSkipView()
                            //.disableSqlFilter()
                            //.likeTable()
                            //.notLikeTable()
                            
                            .controllerBuilder()
                            .enableRestStyle()
                            .enableHyphenStyle()
                            //.convertFileName()
                            //.formatFileName("%sController")
                            //.superClass()
                            
                            .serviceBuilder()
                            .formatServiceFileName("%sService")
                            //.convertServiceFileName()
                            //.superServiceClass()
                            //.convertServiceImplFileName()
                            //.formatServiceImplFileName()
                            //.superServiceImplClass()
                            
                            .mapperBuilder()
                            .enableBaseColumnList() // xml 中添加列名列表
                            .enableBaseResultMap()  // xml 中添加BaseResultMap
                            .enableMapperAnnotation()
                            //.superClass()
                            //.convertMapperFileName()
                            //.convertXmlFileName()
                            //.cache()
                            
                            .entityBuilder()
                            .idType(IdType.ASSIGN_UUID)
                            .enableLombok() // 启用 lombok 基础注解
                            //.enableChainModel() // 启用 lombok 链式注解
                            .enableColumnConstant() // 在 实体类 中添加 数据库列名常量（可用于 wrapper 构造）
                            .enableTableFieldAnnotation()
                            //.enableActiveRecord();
                            //.enableRemoveIsPrefix()
                            //.disableSerialVersionUID()
                            //.superClass("MyBaseEntity")
                            //.addSuperEntityColumns("id", "created_by", "created_time", "updated_by", "updated_time")
                            //.columnNaming(NamingStrategy.underline_to_camel)
                            //.naming(NamingStrategy.underline_to_camel)
                            //.nameConvert()
                            //.convertFileName()
                            .versionColumnName(VersionColumnName)
                            .versionPropertyName(VersionPropertyName)
                            .logicDeleteColumnName(LogicDeleteColumnName)
                            .logicDeletePropertyName(LogicDeletePropertyName)
                            .addIgnoreColumns(delimitedStringToStringArray(IgnoreColumns))
                            .addTableFills(new Column(CreateTimeColumnName, FieldFill.INSERT))
                            .addTableFills(new Column(UpdateTimeColumnName, FieldFill.INSERT_UPDATE));
                })
                // 将同名的模板文件放在test/resources相同路径下可以无需配置模板路径，优先使用你自定义的模板文件
                //.templateConfig(builder -> {
                //    builder.entity("/templates/entity.java");
                //})
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板，默认的是Velocity引擎模板
                .execute();
    }
    
    /**
     * 获取文件系统路径
     *
     * @return
     */
    private static String getCanonicalPath() {
        File directory = new File("");//参数为空
        String courseFile = null;
        try {
            courseFile = directory.getCanonicalPath();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("项目路径: " + courseFile);
        System.out.println();
        return courseFile;
    }
    
    private static List<String> delimitedStringToStringList(String delimitedString) {
        String[] split = delimitedString.split(",");
        List<String> itemList = Arrays.stream(split).map(item -> {
            return item.trim();
        }).collect(Collectors.toList());
        return itemList;
    }
    
    private static String[] delimitedStringToStringArray(String delimitedString) {
        List<String> stringList = delimitedStringToStringList(delimitedString);
        String[] sa = stringList.toArray(new String[0]);
        return sa;
    }
    
    
    private static final String DATASOURCE_URL_STANDARD = "jdbc:mysql://localhost:3306/demo_tree?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
}

